import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)
import java.util.*;

/**
 * This class represents StackMans archenemy, the poor haunted souls wandering 'round, trying to get him.
 * 
 * @author (Thomas KOBER)
 * @author (Dilyan GEORGIEV)
 * 
 * @version (1.0)
 */
public class Ghost extends Actor
{
    
    private static final int WALL_HIT       = 30;
    private static final int OBJECT_HIT     = 6;
    private static final int HEADER_OFFSET  = 50;
    private static final int RANGE          = 65;
    
    /**
     * Act - do whatever the Ghost wants to do. This method is called whenever
     * the 'Act' or 'Run' button gets pressed in the environment.
     */
    public void act() 
    {   
        if(!((StackWorld)super.getWorld()).isPaused()) {
            move(1);
            wander();
        }
        
    }
    
    /**
     * Method to get the right side of the Ghost Object.
     * @return the right border of the Ghost Object.
     */
    private int getGhostRight() {
        return super.getX() + (super.getImage().getWidth()/2);
    }

    /**
     * Method to get the top side of the Ghost Object.
     * @return the top border of the Ghost Object.
     */
    private int getGhostTop()   {
        return super.getY() + (super.getImage().getHeight()/2);
    }

    /**
     * Method to get the bottom side of the Ghost Object.
     * @return the bottom border of the Ghost Object.
     */
    private int getGhostBot()   {
        return super.getY() - (super.getImage().getHeight()/2);
    }

    /**
     * Method to get the left side of the Ghost Object.
     * @return the left border of the Ghost Object.
     */
    private int getGhostLeft()  {
        return super.getX() - (super.getImage().getWidth()/2);
    }
    
    /**
     * Method that checks if there is an item on the right side of the Ghost.
     * @return if there is an object.
     */
    private boolean impactRight() {
        boolean item = false; 
        int origX = super.getX();
        int origY = super.getY();
        int x = super.getX() + super.getImage().getWidth()/2;
        setLocation(x, getY());
        Actor t = getOneIntersectingObject(Obstacle.class);
        Obstacle k = (Obstacle)t;
        if(t != null) {
            item = true;
        }
        setLocation(origX,origY);
        return item;
    }
    
    /**
     * Checks if there is an obstacle on the left side of the Ghost.
     * @return if there is an obstacle.
     */
    private boolean impactLeft() {
        boolean item = false; 
        int origX = super.getX();
        int origY = super.getY();
        int x = super.getX() - super.getImage().getWidth()/2;
        setLocation(x, getY());
        Actor t = getOneIntersectingObject(Obstacle.class);
        Obstacle k = (Obstacle)t;
        if(t != null) {
            item = true;
        }
        setLocation(origX,origY);
        return item;
    }
    
    /**
     * Checks if there is an obstacle above the Ghost.
     * @return if there is an obstacle.
     */

    private boolean impactTop() {
        boolean item = false; 
        int origX = super.getX();
        int origY = super.getY();
        int y = super.getY() - super.getImage().getWidth()/2;
        setLocation(getX(), y);
        Actor t = getOneIntersectingObject(Obstacle.class);
        Obstacle k = (Obstacle)t;
        if(t != null) {
            item = true;
        }
        setLocation(origX,origY);
        return item;
    }    
    
    /**
     * Check if there is an obstacle below the Ghost.
     * @return if there is an obstacle.
     */
    private boolean impactBot() {
        boolean item = false; 
        int origX = super.getX();
        int origY = super.getY();
        int y = super.getY() + super.getImage().getHeight()/2;
        setLocation(getX(), y);
        Actor t = getOneIntersectingObject(Obstacle.class);
        Obstacle k = (Obstacle)t;
        if(t != null) {
            item = true;
        }
        setLocation(origX,origY);
        return item;
    }
    
    /**
     * Check if there is an obstacle in teh direction which the Ghost is going.
     * @return if there is a hit.
     */
    private boolean checkImpactAhead() {
        boolean hit = false;
        int origX = super.getX();
        int origY = super.getY();
        int dir = super.getRotation();
        if(dir == 0 ) {
            setLocation(super.getX() + 10, super.getY());
        } else if (dir == 90 ) {
            setLocation(super.getX(), super.getY() + 10);
        } else if (dir == 180) {
            setLocation(super.getX() - 10 , super.getY());
        } else if (dir == 270) {
            setLocation(super.getX(), super.getY() - 10);
        }
        Actor actor;
        actor = getOneIntersectingObject(Obstacle.class);
        if(actor != null) {
            hit = true;
        }
        setLocation(origX, origY);
        return hit;
    }
    
    /**
     * This gets the Ghost wandering around.
     */
    private void wander()   {
        
        ///////////////////////////////////
        //Gets the Direction of the Ghost//
        ///////////////////////////////////
        boolean moveRight = super.getRotation() == 0;        
        boolean moveDown = super.getRotation() == 90;
        boolean moveLeft = super.getRotation() == 180;
        boolean moveUp = super.getRotation() == 270;
        
        
        ///////////////////////////////////////////////////
        //Checks the bounds of the Ghost within the walls//
        ///////////////////////////////////////////////////
        boolean yTopBound = this.getY() <= WALL_HIT + HEADER_OFFSET; //Includes the print out area for the points.
        boolean yBotBound = this.getY() >= getWorld().getHeight() - WALL_HIT;
        boolean xRightBound = this.getX() >= getWorld().getWidth() - WALL_HIT;
        boolean xLeftBound = this.getX() <= WALL_HIT;
        
        //////////////////////////////////////
        //Sets the movement around the walls//
        //////////////////////////////////////
        if ((yTopBound && moveUp ) || (yBotBound &&  moveDown)) { //It will check the vertical bounds.
            if (impactRight()) { //if there is an item to the right it will turn left.
                setRotation(180);
            } else if(impactLeft()) { //if there is an item to the left it will turn right.
                setRotation(0);
            } else { //it will pick random if there are no obstacles around both sides.
                if(Greenfoot.getRandomNumber(2) == 1) { 
                    setRotation(0);
                } else {
                    setRotation(180);                
                }
            }
        } else if ((xRightBound && moveRight) || (xLeftBound  && moveLeft)) { //It will check the horizontal bounds.
            if (impactTop() && yTopBound) { //This will check if there is any object on the top, and also if it has hit the top wall bound
                setRotation(90);
            } else if (impactBot() && yBotBound) { //This will check if there are any objects on the bottom of the Ghost, and also it will check if it hits the bottom wall.
                setRotation(270);
            } else { //Else it will pick the random if there are no obstacles at both ends.
                if (Greenfoot.getRandomNumber(2) == 1) {
                    setRotation(90);
                } else {
                    setRotation(270);
                }
            }
        } else { //if the impact is not against a wall it will check for an impact against an object.

            if(checkImpactAhead()) { // checks if there is an impact if front of the Ghost.
                if ( impactTop() && !impactBot() && (moveRight || moveLeft) ) { //If there is an item on the top (and not on the bottom) and if the ghost is moving left or right.
                    setRotation(90);
                } else if (impactBot() && !impactTop() && (moveRight || moveLeft) ) { //If there is an item on the bot (and not on the top) and if the ghost is moving left or right.
                    setRotation(270);
                } else if(impactRight() && !impactLeft() && (moveUp || moveDown)) {
                    setRotation(180);
                } else if (impactLeft()&& !impactRight() && (moveUp || moveDown)) {
                    setRotation(0);
                } else if (moveRight || moveLeft) {
                    if (Greenfoot.getRandomNumber(2) == 1) {
                        setRotation(90);
                    } else {
                        setRotation(270);
                    }
                } else {
                    if(Greenfoot.getRandomNumber(2) == 1) {
                        setRotation(0);
                    } else {
                        setRotation(180);                
                    }
                }

            }
        }

    }

    public void setDirection(int dir)
    {
        super.setRotation(dir);
    }
}
